#ifndef Srever_h__
#define Srever_h__

#include <boost/asio.hpp>
#include "Connection.h"
#include "ConnectionManager.h"
#include "ConnectionListener.h"
#include "RpcConnection.h"
#include "../Common/Timer.h"


class Server : public ConnectionClosedListener,
		 private boost::noncopyable
{
public:
	/// Construct the server to listen on the specified TCP address and port, and
	/// serve up files from the given directory.
	Server();

	template<typename T>
	void listen(const std::string& address, const std::string& port, T conn_template);
	
	/// Run the server's io_service loop.
	void run();

	void stop();

	boost::asio::io_service& getIoService()
	{
		return io_service_;
	}

	virtual void onConnClosed(ConnectionPtr c);

protected:
	void onUpdate(const boost::system::error_code& error);
	void doUpdate();

private:
	/// Initiate an asynchronous accept operation.
	void startAccept();

	/// Handle completion of an asynchronous accept operation.
	void handleAccept(const boost::system::error_code& e);

	/// Handle a request to stop the server.
	void handleStop();

	/// The io_service used to perform asynchronous operations.
	boost::asio::io_service io_service_;

	/// Acceptor used to listen for incoming connections.
	boost::asio::ip::tcp::acceptor acceptor_;

	/// The connection manager which owns all live connections.
	ConnectionManager connection_manager_;

	/// The next connection to be accepted.
	ConnectionPtr new_connection_;

	volatile bool stopped_;

	ConnectionPtr connection_template;

	uint32 last_update_time;
	boost::asio::deadline_timer update_timer_;
};

template<typename T>
void Server::listen(const std::string& address, const std::string& port, T conn_template)
{
	connection_template = conn_template;
	// Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR).
	boost::asio::ip::tcp::resolver resolver(io_service_);
	boost::asio::ip::tcp::resolver::query query(address, port);
	boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
	acceptor_.open(endpoint.protocol());
	acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
	acceptor_.bind(endpoint);
	acceptor_.listen();

	startAccept();
}

#endif // Srever_h__


